﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;

namespace AppConfigDataProxy
{
    /// <summary>
    /// helpfull function for convertion from class in System.Xml.Linq to System.Xml
    /// </summary>
    static class Helper
    {
        /// <summary>
        /// Convert XmlElement to XElement
        /// </summary>
        public static XElement GetXElement(this XmlElement node)
        {
            XDocument xDoc = new XDocument();
            using (XmlWriter xmlWriter = xDoc.CreateWriter())
                node.WriteTo(xmlWriter);
            return xDoc.Root;
        }

        /// <summary>
        /// Convert XElement to XmlElement
        /// </summary>
        public static XmlElement GetXmlElement(this XElement element)
        {
            using (XmlReader xmlReader = element.CreateReader())
            {
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.Load(xmlReader);
                return xmlDoc.DocumentElement;
            }
        }

        /// <summary>
        /// Convert XmlElement to XmlSchema
        /// </summary>
        public static XmlSchema GetXmlSchema(this XmlElement node)
        {
            XmlSchema xmlSchema = null;
            XDocument xDoc = new XDocument();
            using (XmlWriter xmlWriter = xDoc.CreateWriter())
                node.WriteTo(xmlWriter);
            using (XmlReader reader = xDoc.CreateReader())
            {
                xmlSchema = XmlSchema.Read(reader,
                    (sender, validationEventArgs) =>
                    {
                        if (validationEventArgs.Severity == XmlSeverityType.Error)
                            throw new ArgumentException(validationEventArgs.Message);
                    });              
            }

            return xmlSchema;
        }


        /// <summary>
        /// Convert XElement to XmlSchema
        /// </summary>
        public static XmlSchema GetXmlSchema(this XElement element)
        {
            XmlSchema xmlSchema = null;
            using (XmlReader xmlReader = element.CreateReader())
            {
                xmlSchema = XmlSchema.Read(xmlReader,
                    (sender, validationEventArgs) =>
                    {
                        if (validationEventArgs.Severity == XmlSeverityType.Error)
                            throw new ArgumentException(validationEventArgs.Message);
                    });  
            }
            return xmlSchema;
        }

        /// <summary>
        /// Check is XmlElement valid XmlSchema
        /// </summary>
        /// <param name="node"></param>
        /// <param name="errorMessage">return error message string if XmlElement is not valid XmlSchema</param>
        /// <returns>return true if valid</returns>
        public static bool IsValidXmlSchema(this XmlElement node, out string errorMessage)
        {
            
            bool errors = false;
            string errorsString = null;

            XDocument xDoc = new XDocument();
            using (XmlWriter xmlWriter = xDoc.CreateWriter())
                node.WriteTo(xmlWriter);
            using (XmlReader reader = xDoc.CreateReader())
            {
                XmlSchema.Read(reader,
                    (sender, validationEventArgs) =>
                    {
                        if (validationEventArgs.Severity == XmlSeverityType.Error)
                            errors = true;  
                         
                        errorsString = validationEventArgs.Message;
                    });
            }

            //return error message
            errorMessage = errorsString;

            return (errors == false);
        }

        /// <summary>
        /// Validate  XmlElement with XmlSchema
        /// </summary>
        /// <param name="node"></param>
        /// <param name="errorMessage">return error message string if XmlElement is not valid</param>
        /// <returns>return true if valid</returns>
        public static bool IsValidXmlElement(this XmlElement node, XmlSchema schema, out string errorMessage)
        {            
             
            XDocument xmlDoc = new XDocument();
            
            using (XmlWriter xmlWriter = xmlDoc.CreateWriter())
                node.WriteTo(xmlWriter);
            //xmlDoc.Schemas.Add(schema);
            XmlSchemaSet xmlSchemaSet = new XmlSchemaSet();
            xmlSchemaSet.Add(schema);

            bool errors = false;
            string errorsString = null;
            xmlDoc.Validate(xmlSchemaSet,
                (sender, validationEventArgs) =>
                {
                    if (validationEventArgs.Severity == XmlSeverityType.Error)
                        errors = true;

                    errorsString = validationEventArgs.Message;                
                });

            //return error message
            errorMessage = errorsString;

            return (errors == false);
        }

        /// <summary>
        /// Validate  App Config with XmlSchema
        /// </summary>
        public static void ValidateApp(this AppInfo appInfo, XmlSchema schema )
        {
            //validate app config with schema
            string errDesription;
            bool isValid = Helper.IsValidXmlElement(appInfo.Config, schema, out errDesription);

            //throw exception if app config is not valid
            if (isValid == false)
            {
                string errMes = ResourceErrorMessage.InvalidAppConfig + errDesription;
                throw new ArgumentException(errMes, "appInfo.Config");
            }
        }

    }



}
